package co.com.jtune.view.util;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import org.apache.commons.beanutils.PropertyUtils;


/**
 * Clase utilitaria para realizar operaciones con reflection.
 * @author ferruccin
 *
 */
public class ReflectionClientUtils {
	
	/**
	 * Obtienen el valor de una propiedad de un objeto mediando el uso de reflextion
	 * @param model Objeto que contiene la propiedad.
	 * @param property nombre de la propiedad.
	 * @return El valor de la propiedad.
	 * obtenerValorDefault
	 */
	public static Object getPropertyValue(Object model, String property) {
		Object valor = "";
		try {
			valor = PropertyUtils.getProperty(model, property);
		} catch (IllegalAccessException e) {
			System.out.println(
					"No se tuvo acceso a la propiedad " + property
					+ " de la clase " + model.getClass().toString());
		} catch (InvocationTargetException e) {
			System.out.println(
					"No se pudo invocar a la propiedad " + property
					+ " de la clase " + model.getClass().toString());
		} catch (NoSuchMethodException e) {
			System.out.println(
					"La clase" + model.getClass().toString()
					+ " no tiene el setter para la propiedad "
					+ property);
		}
		return valor;
	}
	
	/**
	 * Asigna un valor a una propiedad de un objeto
	 * @param model objeto que contiene la propiedad.
	 * @param property Nombre de la propiedad.
	 * @param nuevoValor El valor a asiganar a la propiedad.
	 * asignarNuevoValor
	 */
	public static void assignNewPropertyValue(Object model, String property, Object nuevoValor) {
		try {
			PropertyUtils.setProperty(model, property, nuevoValor);
		} catch (IllegalAccessException e) {
			System.out.println("No se tuvo acceso a la propiedad " + property + " de la clase " + model.getClass().toString());
		} catch (InvocationTargetException e) {
			System.out.println("No se pudo invocar a la propiedad " + property + " de la clase " + model.getClass().toString());
		} catch (NoSuchMethodException e) {
			System.out.println("La clase" + model.getClass().toString() + " no tiene el setter para la propiedad " + property);
		}
	}
	
	/***
	 * Retorna el tipo de dato de la propiedad "property" del objecto "object"
	 * @param object Objete que tiene la propiedad 
	 * @param property propiedad que se quiere saber el tipo
	 * @return Una objeto Class con el tipo de dato de la propiedad
	 * obtenerClasePropiedad
	 */
	public static Class<?> getPropertyClass(Object object, String property) {
		Class<?> clase = null;
		try {
			clase = PropertyUtils.getPropertyType(object, property);
		} catch (IllegalAccessException e) {
			String msj = "No se tuvo acceso a la propiedad " + property + " de la clase " + object.getClass().toString();
			System.out.println(msj);
			throw new RuntimeException(msj, e);
		} catch (InvocationTargetException e) {
			String msj = "No se pudo invocar a la propiedad " + property + " de la clase " + object.getClass().toString();
			System.out.println(msj);
			throw new RuntimeException(msj, e);
		} catch (NoSuchMethodException e) {
			String msj = "La clase" + object.getClass().toString() + " no tiene el getter para la propiedad " + property;
			System.out.println(msj);
			throw new RuntimeException(msj, e);
		}
		return clase;
	}
	
	/**
	 * Crea una inatancia del tipo especificado. La clase debe
	 * tener un constructor por defecto. Si no puede crear una instancia
	 * tira una excepcion.
	 * @param <T>
	 * @param type
	 * @return
	 * @throws IllegalArgumentException si no puede instanciar el objeto. 
	 */
	public static <T> T createInstance(Class<T> type) {
		try {
			Constructor<T> constructor = type.getConstructor(new Class[0]);
			return constructor.newInstance(new Object[0]);
		} catch (SecurityException e) {
			throw new IllegalArgumentException("No se puede crear una instancia de "+type.getName());
		} catch (NoSuchMethodException e) {
			throw new IllegalArgumentException("No se puede crear una instancia de "+type.getName());
		} catch (IllegalArgumentException e) {
			throw new IllegalArgumentException("No se puede crear una instancia de "+type.getName());
		} catch (InstantiationException e) {
			throw new IllegalArgumentException("No se puede crear una instancia de "+type.getName());
		} catch (IllegalAccessException e) {
			throw new IllegalArgumentException("No se puede crear una instancia de "+type.getName());
		} catch (InvocationTargetException e) {
			throw new IllegalArgumentException("No se puede crear una instancia de "+type.getName());
		}
	}	

}
